/**
 * Chat Room Application - Main entry point
 */
import { DataTransfer, URLUtils, NavigationUtils, ErrorHandler, ValidationUtils } from '../common/storage.js';
import { SessionManager } from '../common/sessionManager.js';
import { DOMUtils, AsyncUtils } from '../common/utils.js';
import { roomAPI, ApiUtils } from '../common/api.js';
import { ChatWebSocketManager } from './websocket.js';
import { ChatUIManager } from './ui.js';

class ChatRoomApp {
    constructor() {
        this.isInitialized = false;
        this.session = null;
        this.roomData = null;
        
        this.wsManager = new ChatWebSocketManager();
        this.uiManager = null;
        this.elements = {};
        
        this.init();
    }

    async init() {
        console.log('Initializing Chat Room Application...');
        
        try {
            // Wait for DOM to be ready
            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', () => this.setupApp());
            } else {
                this.setupApp();
            }
        } catch (error) {
            console.error('Failed to initialize chat room:', error);
            this.handleFatalError('Failed to initialize application');
        }
    }

    async setupApp() {
        try {
            this.cacheElements();
            this.setupEventListeners();
            
            // Check for persisted session first
            const persistedSession = SessionManager.getPersistedSession();
            
            if (persistedSession && persistedSession.roomId) {
                console.log('Found persisted session, attempting automatic rejoin...');
                await this.attemptAutomaticRejoin(persistedSession);
            } else {
                // No session found, try legacy validation
                await this.validateAndJoinRoom();
            }
            
            this.isInitialized = true;
            console.log('Chat room application initialized successfully');
            
        } catch (error) {
            console.error('Setup error:', error);
            this.handleFatalError(error.message || 'Application setup failed');
        }
    }

    cacheElements() {
        this.elements = {
            loadingScreen: DOMUtils.getElementById('loading-screen'),
            errorDisplay: DOMUtils.getElementById('error-display'),
            errorMessage: DOMUtils.getElementById('error-message'),
            errorRetry: DOMUtils.getElementById('error-retry'),
            errorHome: DOMUtils.getElementById('error-home'),
            roomContainer: DOMUtils.getElementById('room-container')
        };
    }

    setupEventListeners() {
        // Error handling
        DOMUtils.addEventListener(this.elements.errorRetry, 'click', () => this.retryConnection());
        DOMUtils.addEventListener(this.elements.errorHome, 'click', () => NavigationUtils.goHome());
        
        // Custom events from UI manager
        document.addEventListener('send-message', (e) => this.handleSendMessage(e.detail));
        document.addEventListener('leave-room', () => this.handleLeaveRoom());
        document.addEventListener('show-error', (e) => this.showError(e.detail.message));

        // WebSocket events
        this.wsManager.on('connected', () => this.handleWebSocketConnected());
        this.wsManager.on('disconnected', (data) => this.handleWebSocketDisconnected(data));
        this.wsManager.on('joinSuccess', (data) => this.handleJoinSuccess(data));
        this.wsManager.on('newMessage', (data) => this.handleNewMessage(data));
        this.wsManager.on('userJoined', (data) => this.handleUserJoined(data));
        this.wsManager.on('userLeft', (data) => this.handleUserLeft(data));
        this.wsManager.on('roomUpdate', (data) => this.handleRoomUpdate(data));
        this.wsManager.on('serverError', (data) => this.handleServerError(data));
        this.wsManager.on('reconnecting', (data) => this.handleReconnecting(data));
        this.wsManager.on('reconnectFailed', () => this.handleReconnectFailed());

        // Page visibility handling
        document.addEventListener('visibilitychange', () => this.handleVisibilityChange());
        
        // Before unload warning
        window.addEventListener('beforeunload', (e) => this.handleBeforeUnload(e));
    }

    /**
     * Attempt automatic room rejoin using persisted session
     * @param {Object} sessionData Persisted session data
     */
    async attemptAutomaticRejoin(sessionData) {
        try {
            // Show recovery UI
            this.showRecoveryScreen(sessionData);
            
            // Validate session with server
            const validation = await SessionManager.validateSessionWithServer(sessionData);
            
            if (validation.valid) {
                // Session is still valid, proceed with rejoin
                await this.executeRoomRejoin(sessionData, validation.roomData);
            } else if (validation.roomExists) {
                // Room exists but session expired, prompt for rejoin
                await this.promptRoomRejoin(validation.room);
            } else {
                // Room no longer exists
                this.handleRoomNotFound(sessionData);
            }
        } catch (error) {
            console.error('Automatic rejoin failed:', error);
            this.fallbackToHomepage(error);
        }
    }

    /**
     * Execute room rejoin with valid session
     * @param {Object} sessionData Original session data
     * @param {Object} roomData Server validation response
     */
    async executeRoomRejoin(sessionData, roomData) {
        // Update session with fresh data
        this.session = {
            ...sessionData,
            ...roomData.userSession
        };
        
        // Update room data
        this.roomData = roomData.room;
        
        // Initialize UI manager
        this.uiManager = new ChatUIManager();
        this.uiManager.updateRoomInfo(this.roomData);
        
        // Connect WebSocket and rejoin
        await this.connectWebSocketAndRejoin();
        
        // Update UI state
        this.showRoomContainer();
        this.uiManager.addSystemMessage('Welcome back! You have been reconnected to the room.');
        
        // Update persisted session with fresh data
        SessionManager.persistRoomSession(this.roomData, this.session);
    }

    /**
     * Prompt user to rejoin room when session expired
     * @param {Object} roomData Room information
     */
    async promptRoomRejoin(roomData) {
        // Clear invalid session
        SessionManager.clearSession();
        
        // Redirect to homepage with room info for manual rejoin
        const params = {
            roomId: roomData.id,
            rejoin: 'session_expired',
            message: 'Your session has expired. Please join the room again.'
        };
        
        NavigationUtils.goHome(params);
    }

    /**
     * Handle room not found scenario
     * @param {Object} sessionData Session data
     */
    handleRoomNotFound(sessionData) {
        SessionManager.clearSession();
        
        const params = {
            error: 'room_not_found',
            message: `The room "${sessionData.roomName || 'Unknown'}" is no longer available.`
        };
        
        NavigationUtils.goHome(params);
    }

    /**
     * Show recovery screen while attempting rejoin
     * @param {Object} sessionData Session data
     */
    showRecoveryScreen(sessionData) {
        const container = this.elements.loadingScreen;
        if (container) {
            container.innerHTML = `
                <div class="recovery-message">
                    <div class="spinner"></div>
                    <h3>Reconnecting to ${sessionData.roomName || 'your room'}...</h3>
                    <p>Please wait while we restore your session.</p>
                </div>
            `;
            DOMUtils.show(container);
        }
    }

    /**
     * Show room container and hide loading
     */
    showRoomContainer() {
        DOMUtils.hide(this.elements.loadingScreen);
        DOMUtils.show(this.elements.roomContainer);
    }

    /**
     * Connect WebSocket for automatic rejoin
     */
    async connectWebSocketAndRejoin() {
        try {
            const wsUrl = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/ws`;
            
            await this.wsManager.connect(wsUrl);
            
            // Join room via WebSocket with existing userId for reconnection
            this.wsManager.joinRoom(
                this.session.roomId,
                this.session.nickname,
                null, // password not needed for reconnection
                this.session.userId
            );
            
        } catch (error) {
            console.error('WebSocket connection failed during rejoin:', error);
            throw new Error('Failed to reconnect to chat server');
        }
    }

    /**
     * Fallback to homepage when rejoin fails
     * @param {Error} error Error that caused fallback
     */
    fallbackToHomepage(error) {
        console.error('Fallback to homepage:', error);
        SessionManager.clearSession();
        
        const params = {
            error: 'rejoin_failed',
            message: 'Unable to reconnect to your previous room. Please join again.'
        };
        
        NavigationUtils.goHome(params);
    }
    

    async validateAndJoinRoom() {
        // Get session data
        this.session = DataTransfer.getSession();
        const params = URLUtils.getParams();
        
        // Check for session data
        if (!this.session || !ValidationUtils.isValidSession(this.session)) {
            // Check URL parameters as fallback
            if (params.roomId && ValidationUtils.isValidRoomId(params.roomId)) {
                throw new Error('Session expired. Please join the room again.');
            } else {
                throw new Error('No valid session found. Please return to homepage.');
            }
        }

        try {
            // Validate session with server
            const validation = await roomAPI.validateSession(
                this.session.roomId,
                this.session.userId,
                this.session.sessionToken
            );

            if (!validation.valid) {
                throw new Error('Session is no longer valid');
            }

            // Get room information
            this.roomData = await roomAPI.getRoomInfo(this.session.roomId);
            
            // Initialize UI manager
            this.uiManager = new ChatUIManager();
            
            // Update UI with room info
            this.uiManager.updateRoomInfo(this.roomData);
            
            // Connect WebSocket
            await this.connectWebSocket();
            
            // Show room container
            DOMUtils.hide(this.elements.loadingScreen);
            DOMUtils.show(this.elements.roomContainer);

        } catch (error) {
            console.error('Session validation failed:', error);
            
            if (error.status === 401 || error.message.includes('session')) {
                ErrorHandler.handleSessionError(error);
            } else {
                ErrorHandler.handleRoomError(error);
            }
        }
    }

    async connectWebSocket() {
        try {
            const wsUrl = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/ws`;
            
            await this.wsManager.connect(wsUrl);
            
            // Join room via WebSocket
            this.wsManager.joinRoom(
                this.session.roomId,
                this.session.nickname,
                null, // password not needed for reconnection
                this.session.userId
            );
            
        } catch (error) {
            console.error('WebSocket connection failed:', error);
            throw new Error('Failed to connect to chat server');
        }
    }

    handleWebSocketConnected() {
        console.log('WebSocket connected');
        this.uiManager.updateConnectionStatus('Connected', true);
        this.uiManager.setInputState(true);
    }

    handleWebSocketDisconnected(data) {
        console.log('WebSocket disconnected:', data);
        this.uiManager.updateConnectionStatus('Disconnected', false);
        this.uiManager.setInputState(false);
    }

    handleJoinSuccess(data) {
        console.log('Successfully joined room via WebSocket:', data);
        
        // Update room and user data
        this.roomData = { ...this.roomData, ...data.room };
        this.uiManager.updateRoomInfo(this.roomData);
        
        // Update users list
        if (data.users) {
            this.uiManager.updateUsersList(data.users);
        }
        
        // Persist successful session
        if (this.roomData && this.session) {
            SessionManager.persistRoomSession(this.roomData, this.session);
        }
        
        // Add welcome message
        this.uiManager.addSystemMessage(`Welcome to ${this.roomData.name}!`);
    }

    handleNewMessage(data) {
        this.uiManager.addMessage(data.message);
    }

    handleUserJoined(data) {
        this.uiManager.handleUserJoined(data);
    }

    handleUserLeft(data) {
        this.uiManager.handleUserLeft(data);
    }

    handleRoomUpdate(data) {
        // Update member count
        if (data.memberCount !== undefined) {
            this.roomData.memberCount = data.memberCount;
            this.uiManager.updateRoomInfo(this.roomData);
        }
        
        // Update users list
        if (data.users) {
            this.uiManager.updateUsersList(data.users);
        }
    }

    handleSendMessage(messageData) {
        const { content } = messageData;
        
        if (!content.trim()) return;
        
        if (this.wsManager.isConnected) {
            const success = this.wsManager.sendMessage(content);
            
            if (!success) {
                this.uiManager.showError('Failed to send message. Please try again.');
            }
        } else {
            this.uiManager.showError('Not connected to server. Please wait...');
        }
    }

    async handleLeaveRoom() {
        try {
            // Send leave message via WebSocket
            if (this.wsManager.isConnected) {
                this.wsManager.leaveRoom();
            }
            
            // Clear session data
            DataTransfer.clearSession();
            
            // Disconnect WebSocket
            this.wsManager.disconnect();
            
            // Navigate to homepage
            NavigationUtils.goHome();
            
        } catch (error) {
            console.error('Error leaving room:', error);
            // Navigate to homepage anyway
            NavigationUtils.goHome();
        }
    }

    handleServerError(data) {
        console.error('Server error:', data);
        this.uiManager.showError(data.message || 'Server error occurred');
    }

    handleReconnecting(data) {
        console.log(`Reconnecting... attempt ${data.attempt}`);
        this.uiManager.updateConnectionStatus(`Reconnecting... (${data.attempt}/${this.wsManager.maxReconnectAttempts})`, false);
    }

    handleReconnectFailed() {
        console.error('Reconnection failed');
        this.showError('Connection lost. Please refresh the page or return to homepage.');
    }

    handleVisibilityChange() {
        if (document.hidden) {
            // Page is hidden, persist session state
            console.log('Page hidden - persisting session');
            this.enterFocusLossMode();
        } else {
            // Page is visible, restore active state
            console.log('Page visible - restoring active state');
            this.exitFocusLossMode();
        }
    }

    /**
     * Enter focus loss mode - persist session and adjust connection
     */
    enterFocusLossMode() {
        // Persist current session state
        if (this.roomData && this.session) {
            SessionManager.persistRoomSession(this.roomData, this.session);
            SessionManager.markSessionAsAway();
        }
        
        // Adjust WebSocket behavior for focus loss
        if (this.wsManager) {
            this.wsManager.adjustHeartbeat('focus_loss');
            this.wsManager.notifyFocusLoss();
        }
    }

    /**
     * Exit focus loss mode - restore active state and validate connection
     */
    exitFocusLossMode() {
        // Update session activity
        SessionManager.markSessionAsActive();
        
        // Restore normal WebSocket behavior
        if (this.wsManager) {
            this.wsManager.adjustHeartbeat('normal');
            this.wsManager.notifyFocusGain();
            
            // Validate connection integrity
            if (this.wsManager.isConnected) {
                this.wsManager.validateConnection().catch((error) => {
                    console.warn('Connection validation failed:', error);
                    this.retryConnection();
                });
            } else if (this.session) {
                this.retryConnection();
            }
        }
    }

    handleBeforeUnload(e) {
        // Always persist session before unload
        if (this.roomData && this.session) {
            SessionManager.prepareForUnload();
            SessionManager.persistRoomSession(this.roomData, this.session);
        }
        
        // Attempt graceful disconnect
        if (this.wsManager && this.wsManager.isConnected) {
            // Send temporary leave notification
            this.wsManager.send('temporary_leave', {
                reason: 'page_unload',
                timestamp: Date.now()
            });
        }
    }

    async retryConnection() {
        try {
            DOMUtils.show(this.elements.loadingScreen);
            DOMUtils.hide(this.elements.errorDisplay);
            
            await this.validateAndJoinRoom();
            
        } catch (error) {
            console.error('Retry failed:', error);
            this.showError(error.message || 'Retry failed');
        }
    }

    showError(message) {
        DOMUtils.setTextContent(this.elements.errorMessage, message);
        DOMUtils.show(this.elements.errorDisplay);
        DOMUtils.hide(this.elements.loadingScreen);
        DOMUtils.hide(this.elements.roomContainer);
    }

    handleFatalError(message) {
        console.error('Fatal error:', message);
        
        // Clear session data
        DataTransfer.clearSession();
        
        // Redirect to homepage with error
        NavigationUtils.goHome({
            error: 'fatal',
            message: encodeURIComponent(message)
        });
    }
}

// Initialize application when script loads
const chatRoomApp = new ChatRoomApp();